﻿using System.Collections.Generic;

namespace GX
{
	public class EventDispatcher:IEventDispatcher
	{
		int _invokingDepth;
		Dictionary<int,int> _toTrimMap;//<eventID,firstEmptyIndex>
		Dictionary<int,List<EventDelegate>> _eventToCallbacksMap = new Dictionary<int, List<EventDelegate>> ();
        
		public void AddEvent (int eventID, EventDelegate del)
		{
			List<EventDelegate> dels;
			if (!_eventToCallbacksMap.TryGetValue (eventID, out dels)) 
            {
                dels = PoolManager.GetList< EventDelegate>(4);
				_eventToCallbacksMap [eventID] = dels;
				dels.Add (del);
				return;
			}
			if (!dels.Contains (del))
				dels.Add (del);
		}

		public void RemoveEvent (int eventID, EventDelegate del)
		{
			List<EventDelegate> dels;
			if (!_eventToCallbacksMap.TryGetValue (eventID, out dels))
				return;
			int len = dels.Count;
			for (int i = 0; i < len; ++i) 
            {
				if (del == dels [i]) 
                {
                    if (0 == _invokingDepth)//不在回调中
                    {
                        dels.RemoveAt(i);
                        if (dels.Count == 0)
                        {
                            _eventToCallbacksMap.Remove(eventID);
                            PoolManager.Release(dels);
                        }
                        return;
                    }
                    //回调过程中移除
                    dels[i] = null;

                    if (null == _toTrimMap)
                        _toTrimMap = PoolManager.GetDictionary<int, int>(4);
 
                    int firstEmptyIndex;
                    if (!_toTrimMap.TryGetValue(eventID, out firstEmptyIndex) || i < firstEmptyIndex)
                        _toTrimMap[eventID] = i;
                    break;
				}
			}
		}

		public void SendEvent (int type, object body,string name=null)
		{
			List<EventDelegate> dels;
			if (!_eventToCallbacksMap.TryGetValue (type, out dels))
				return;
			
			++_invokingDepth;
            Event evt = Event.From(type, body,name);
			int len = dels.Count;
            int index;
            for (index = 0; index < len; ++index)
            {
                var del = dels[index];
				if (null != del) 
                {
                    del(this, type,evt);
				}
			}

            Event.To(evt);
            --_invokingDepth;

            if (0 == _invokingDepth && null != _toTrimMap)//退出调用栈：整理移除掉的回调
            {
                var iter = _toTrimMap.GetEnumerator();
                int key;
                int firstEmptyIndex;
                List<EventDelegate> callList;
                while (iter.MoveNext())
                {
                    key = iter.Current.Key;
                    firstEmptyIndex = iter.Current.Value;

                    _eventToCallbacksMap.TryGetValue(key, out callList);
                    len = callList.Count;

                    index = firstEmptyIndex;

                    for (int i = firstEmptyIndex + 1; i < len; ++i)
                    {
                        var callback = callList[i];
                        if (null != callback)
                        {
                            callList[index++] = callback;
                        }
                    }
                    callList.RemoveRange(index, len - index);
                    if (callList.Count == 0)
                    {
                        _eventToCallbacksMap.Remove(key);
                        PoolManager.Release(callList);
                    }
                }
                PoolManager.Release(_toTrimMap);
                _toTrimMap = null;
            }
		}
	}//end class
}
